﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Input;
using WickedFlame.Core;
using WickedFlame.Core.Shapes;
using WickedFlame.Core.History;

namespace WickedFlame.Core.Tools
{
	public class SelectionTool : VectorTool
	{
		public SelectionTool()
            : base()
        {
        }

		private enum SelectionMode
		{
			None,
			GroupSelection, // group selection is active
			Move,           // object(s) are moves
			Size            // object is resized
		}

		SelectionMode selectMode = SelectionMode.None;
        // Object which is currently resized:
        VectorShape resizedObject;
		int resizeTrackerNo = 0;

        // Keep state about last and current point (used to move and resize objects)
        Point lastPoint = new Point(0, 0);
        Point startPoint = new Point(0, 0);

        WickedFlame.Core.History.HistoryCommand changeCmd;
        bool shapeWasMoved;
        RectangleShape selectionRectangle;

        public override void OnActivate(DrawingCanvas canvas)
        {
            if (canvas.SelectedLayer != null)
                canvas.SelectedLayer.UnselectAll();
        }

        public override void OnMouseLeftButtonDown(DrawingCanvas sender, System.Windows.Input.MouseButtonEventArgs e)
		{
			var point = Mouse.GetPosition(sender);
            changeCmd = null;
            shapeWasMoved = false;

			// Test for resizing (only if control is selected, cursor is on the handle)
            foreach (VectorShape shape in sender.SelectedLayer.ShapeList.Selection)
            {
                //System.Diagnostics.Debug.WriteLine(point);
                int trackerNo = shape.HitTestInt(point);
                //System.Diagnostics.Debug.WriteLine(trackerNo);
                if (trackerNo > 0)
                {
                    selectMode = SelectionMode.Size;

                    // keep resized object in class member
                    resizedObject = shape;
                    resizeTrackerNo = trackerNo;

                    // unselect all objects to resize just one
                    sender.SelectedLayer.ShapeList.UnselectAll();
                    shape.IsSelected = true;

                    DrawingCanvas.DrawTrackers();

                    changeCmd = new WickedFlame.Core.History.SizeChangedCommand(shape, sender.SelectedLayerIndex);

                    break;
                }
            }

            // Test for move (cursor is on the object)
            if (selectMode == SelectionMode.None)
            {
                int n1 = sender.SelectedLayer.ShapeList.Count;
                VectorShape shape = null;

                //for (int i = 0; i < n1; i++)
                for (int i = n1-1; i >= 0; i--)
                {
                    VectorShape tmpShape = sender.SelectedLayer.ShapeList[i] as VectorShape;
                    if (tmpShape.HitTestInt(point) == 0)
                    {
                        shape = tmpShape;
                        break;
                    }
                }

                if (shape != null)
                {
                    selectMode = SelectionMode.Move;

                    // Unselect all if Ctrl is not pressed and clicked object is not selected yet
                    if (!((Keyboard.IsKeyDown(Key.LeftCtrl)) || (Keyboard.IsKeyDown(Key.RightCtrl))) && !shape.IsSelected)
                        sender.SelectedLayer.ShapeList.UnselectAll();

                    //// Select clicked object
                    //shape.Selected = true;

                    if ((Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl)) && shape.IsSelected)
                    {
                        // unselect clicked object
                        shape.IsSelected = false;
                    }
                    else
                    {
                        // Select clicked object
                        shape.IsSelected = true;
                    }
                    
                    DrawingCanvas.DrawTrackers();

                    changeCmd = new WickedFlame.Core.History.MoveCommand(sender.SelectedLayer.ShapeList, sender.SelectedLayerIndex);

                    sender.SelectedLayer.Cursor = Cursors.SizeAll;
                }
            }

            // group selection
            if (selectMode == SelectionMode.None)
            {
                // click on background so unselect all
                if (!(Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl)))
                    sender.SelectedLayer.ShapeList.UnselectAll();

                selectMode = SelectionMode.GroupSelection;
            }

            lastPoint.X = point.X;
            lastPoint.Y = point.Y;
            startPoint.X = point.X;
            startPoint.Y = point.Y;

            // Draw selection rectangle in initial position
            if (selectMode == SelectionMode.GroupSelection)
            {

                if (selectionRectangle != null)
                    sender.TopLayer.RemoveShape(selectionRectangle);

                selectionRectangle = new RectangleShape(startPoint.X, startPoint.Y, 1, 1);
                selectionRectangle.Fill = System.Windows.Media.Brushes.Transparent;
                selectionRectangle.Stroke = System.Windows.Media.Brushes.Black;
                selectionRectangle.StrokeThickness = 0.5;
                //selectionRectangle.StrokeDashArray.Add(5);
                //selectionRectangle.StrokeDashArray.Add(10);

                sender.TopLayer.AddShape(selectionRectangle);
            }

            sender.SelectedLayer.ShapeList.SelectionChanged();
		}

        public override void OnMouseMove(DrawingCanvas sender, System.Windows.Input.MouseEventArgs e)
		{
            var point = Mouse.GetPosition(sender);
            shapeWasMoved = true;

            // set cursor when mouse button is not pressed
            if (e.LeftButton == MouseButtonState.Released)
            {
                Cursor cursor = null;

                for (int i = 0; i < sender.SelectedLayer.ShapeList.Count; i++)
                {
                    VectorShape tmpShape = sender.SelectedLayer.ShapeList[i] as VectorShape;
                    int n = tmpShape.HitTestInt(point);

                    if (tmpShape != null)
                    {
                        if (n > 0)
                        {
                            //cursor = sender.SelectedLayer.ShapeList[i].GetTrackerCursor(n);
                            cursor = tmpShape.GetTrackerCursor(n);
                            break;
                        }
                    }
                }

                if (cursor == null)
                    cursor = Cursors.Arrow;

                sender.SelectedLayer.Cursor = cursor;

                return;
            }

            // resize
            if (selectMode == SelectionMode.Size)
            {
                if (resizedObject != null)
                {
                    //Point m = new Point((int)point.X, (int)point.Y);
                    Point m = new Point(point.X, point.Y);
                    //foreach (VectorShape s in sender.SelectedLayer.ShapeList)
                    //{
                    //    if (s != resizedObject)
                    //    {
                    //        int n = s.HitTestInt(m);
                    //        if (n > 0)
                    //        {
                    //            //check if point is near
                    //            m = s.GetTracker(n);
                    //        }
                    //    }
                    //}

                    //resizedObject.MoveTracker(new Point((int)point.X,(int)point.Y), resizeTrackerNo);
                    resizedObject.MoveTracker(m, resizeTrackerNo);
                    sender.MarkDirty();
                    DrawingCanvas.DrawTrackers();
                }
            }

            // Find difference between previous and current position
            int dx = (int)(point.X - lastPoint.X);
            int dy = (int)(point.Y - lastPoint.Y);

            lastPoint.X = point.X;
            lastPoint.Y = point.Y;

            // move
            if (selectMode == SelectionMode.Move)
            {
                foreach (VectorShape shape in sender.SelectedLayer.ShapeList.Selection)
                {
                    shape.Move(dx, dy);
                    sender.MarkDirty();
                }
                DrawingCanvas.DrawTrackers();
            }
            
            if (selectMode == SelectionMode.GroupSelection)
            {
                //resize the selectionrectangle
                if (selectionRectangle != null)
                {
                    System.Windows.Point m = Mouse.GetPosition(sender);

                    if (m.Y > (selectionRectangle.Y + (selectionRectangle.Height / 2)) &&
                        m.X > (selectionRectangle.X + (selectionRectangle.Width / 2)))//lower right
                        selectionRectangle.MoveTracker(new Point((int)m.X,(int)m.Y), 3);
                    else if (m.Y > (selectionRectangle.Y + (selectionRectangle.Height / 2)) &&
                        m.X < (selectionRectangle.X + (selectionRectangle.Width / 2)))//lower left
                        selectionRectangle.MoveTracker(new Point((int)m.X, (int)m.Y), 4);
                    else if (m.Y < (selectionRectangle.Y + (selectionRectangle.Height / 2)) &&
                        m.X < (selectionRectangle.X + (selectionRectangle.Width / 2)))//upper left
                        selectionRectangle.MoveTracker(new Point((int)m.X, (int)m.Y), 1);
                    else//upper right
                        selectionRectangle.MoveTracker(new Point((int)m.X, (int)m.Y), 2);
                }

                return;
            }
		}

        public override void OnMouseLeftButtonUp(DrawingCanvas sender, System.Windows.Input.MouseButtonEventArgs e)
        {
            if (selectMode == SelectionMode.GroupSelection && selectionRectangle != null)
            {
                //select all objects contained in rectangle
                sender.SelectShapes(
                    RectangleShape.GetNormalizedRectangle(startPoint, lastPoint));
                DrawingCanvas.DrawTrackers();

                sender.TopLayer.RemoveShape(selectionRectangle);
                selectionRectangle = null;
            }

            if (selectMode == SelectionMode.Move || selectMode == SelectionMode.Size)
            {
                if (changeCmd != null && shapeWasMoved)
                {
                    // Keep state after moving/resizing and add command to history
                    if (changeCmd is MoveCommand)
                        ((MoveCommand)changeCmd).SetNewState();
                    if (changeCmd is SizeChangedCommand)
                        ((SizeChangedCommand)changeCmd).SetNewState();
                    sender.PushHistoryCommand(changeCmd);
                    changeCmd = null;

                    var ts = sender.SelectedLayer.ShapeList.TopShape;
                    if (ts != null)
                        ts.CallChangeEndHandler();
                }
            }

            selectMode = SelectionMode.None;
            resizeTrackerNo = 0;
        }

        public override void OnKeyDown(DrawingCanvas sender, KeyEventArgs e)
        {
            if (Mouse.LeftButton != MouseButtonState.Pressed && Mouse.RightButton != MouseButtonState.Pressed)
            {
                if (e.Key == Key.Up ||
                    e.Key == Key.Down ||
                    e.Key == Key.Left ||
                    e.Key == Key.Right)
                {
                    int dx = 0;// (int)(point.X - lastPoint.X);
                    int dy = 0;//(int)(point.Y - lastPoint.Y);

                    if (e.Key == Key.Up)
                    {
                        dy--;
                    }
                    if (e.Key == Key.Down)
                    {
                        dy++;
                    }
                    if (e.Key == Key.Left)
                    {
                        dx--;
                    }
                    if (e.Key == Key.Right)
                    {
                        dx++;
                    }

                    PixelMoveCommand command = new PixelMoveCommand(sender.SelectedLayer.ShapeList, sender.SelectedLayerIndex);

                    foreach (VectorShape shape in sender.SelectedLayer.ShapeList.Selection)
                    {
                        shape.Move(dx, dy);
                    }

                    command.SetNewState();
                    sender.PushHistoryCommand(command);

                    DrawingCanvas.DrawTrackers();
                }
            }
        }
	}
}
